use std::str;
use serde::{Serialize};
use serde::de::DeserializeOwned;
use short_crypt::ShortCrypt;
use serde_json::Value;
use crate::types::SwapData;

/// 本项目中只采用相对低级的加密/解密方
/// 如果你需要定制自己的数据加密方式, 可以修改 encrypt 函数
/// 如果你需要定制自己的数据解密方式, 可以修改 decrypt_string/decrypt 函数
const KEY_PR: &'static str = "A391D)@!9sdk#ayS$*#6123#lVB@^?<5"; // key, 32位长度

/// 将结构体进行加密
pub fn encrypt<T: Serialize>(obj: &T) -> Result<SwapData, &'static str> {
    let value = if let Ok(v) = serde_json::to_string(obj) { v } else {
        return Err("将结构体序列化时出错");
    };
    let sc = ShortCrypt::new(KEY_PR);
    let encrypt_string = sc.encrypt_to_url_component(&value);
    let json_data = SwapData{
        data: encrypt_string,
    };
    Ok(json_data)
}

/// 将结构体转换为 serde_json::Value
pub fn encrypt_to_value<T: Serialize>(object: &T) -> Value {
    if let Ok(v) = encrypt(object) {
        v.to_json()
    } else {
        json!({"data": "Error: 加密信息出现问题"})
    }
}

/// 对字符串进行解密 -> 生成待二次解密的 swap data
pub fn decrypt_string(encrypt_string: &str) -> Result<String, &'static str> {
    let sc = ShortCrypt::new(KEY_PR);
    match sc.decrypt_url_component(encrypt_string) {
        Ok(v) => {
            match String::from_utf8(v) {
                Ok(s) => Ok(s),
                Err(_) => {
                    Err("反解析字符串时出错")
                }
            }
        },
        Err(_) => {
            Err("反解密字符串时出错")
        }
    }
}

/// 对内容进行解密
pub fn decrypt<T: DeserializeOwned>(sd: &SwapData) -> Result<T, &'static str> {
    // 先把 sd.data 进行解密
    let decrypt_str = match decrypt_string(&sd.data) {
        Ok(v) => { v },
        Err(err) => { return Err(err); }
    };
    let object: T = if let Ok(v) = serde_json::from_str(&decrypt_str) { v } else {
        return Err("反解析数据时出错");
    };
    Ok(object)
}

/// 将结构体直接转换为json对象
#[macro_export]
macro_rules! encrypt_struct {
    ($type: tt :: $data: expr) => {{
        let data = $crate::crypt::encrypt::<$type>($data).unwrap();
        data.to_json()
    }}
}
